﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace CoolCode.Linq.Expressions
{
    public static class ExpressionExtensions
    {
        #region Invoke

        public static TResult Invoke<TResult>(this Expression<Func<TResult>> expr)
        {
            return expr.Compile().Invoke();
        }

        public static TResult Invoke<T1, TResult>(this Expression<Func<T1, TResult>> expr, T1 arg1)
        {
            return expr.Compile().Invoke(arg1);
        }

        public static TResult Invoke<T1, T2, TResult>(this Expression<Func<T1, T2, TResult>> expr, T1 arg1, T2 arg2)
        {
            return expr.Compile().Invoke(arg1, arg2);
        }

        public static TResult Invoke<T1, T2, T3, TResult>(this Expression<Func<T1, T2, T3, TResult>> expr, T1 arg1, T2 arg2, T3 arg3)
        {
            return expr.Compile().Invoke(arg1, arg2, arg3);
        }

        public static TResult Invoke<T1, T2, T3, T4, TResult>(this Expression<Func<T1, T2, T3, T4, TResult>> expr, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            return expr.Compile().Invoke(arg1, arg2, arg3, arg4);
        }

        #endregion
        
        public static ConstantExpression GetNullConstant(this Type type)
        {
            return Expression.Constant(null, type.GetNullAssignableType());
        }

        public static void SetValue<T>(this object obj, string propertyName, object propertyValue)
        {
            ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
            ParameterExpression value = Expression.Parameter(typeof(string), "propertyValue");
            MethodInfo setter = typeof(T).GetMethod("set_" + propertyName);
            MethodCallExpression call = Expression.Call(parameter, setter, value);
            LambdaExpression lambda = Expression.Lambda(call, parameter, value);
            var exp = lambda.Compile();
            exp.DynamicInvoke(obj, propertyValue);
        }

        //public static object CreateInstance(this Type type)
        //{
        //    return ExpressionActivator.CreateInstance(type);
        //}

        //public static object CreateInstance(this Type type, params  object[] args)
        //{
        //    return ExpressionActivator.CreateInstance(type, args );
        //}

        //public static T CreateInstance<T>(this Type type ) where T : class
        //{
        //    return CreateInstance(type) as T;
        //}
    }
}
